package com.summer.safe.config.aop.datafilter;

import com.alibaba.fastjson.JSON;
import com.summer.safe.utils.LogUtils;
import com.summer.safe.base.BaseEntity;
import com.summer.safe.config.annotation.DataFilter;
import com.summer.safe.config.datafilter.TableName;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * 数据过滤AOP
 */
@Aspect
@Component
public class DataAspect {
    private final Logger logger = LoggerFactory.getLogger(DataAspect.class);
    private static final ThreadLocal<Long> startTimeThreadLocal =
            new NamedThreadLocal<Long>("ThreadLocal StartTime");

    /**
     * 定义切点Pointcut
     */
    @Pointcut("@annotation(com.summer.safe.config.annotation.DataFilter)")
    private void pointCutMethod() {

    }

    /**
     * 前置通知 用于拦截Service层注入数据过滤
     *
     * @param
     */
    @Around("pointCutMethod()")
    public Object process(ProceedingJoinPoint point) throws Throwable {
        logger.info("aop数据过滤已经拦截该方法:{}",point.getSignature().getName());
        String classType = point.getTarget().getClass().getName();
        Class c =  Class.forName(classType);
        Method[] methods = c.getMethods();
        HashMap tNameMap = new HashMap<String,String>();
        String type = "";
        for (Method method : methods) {
            if(method.isAnnotationPresent(DataFilter.class)){
                tNameMap.put(TableName.PRIMARY,method.getAnnotation(DataFilter.class).primary());
                tNameMap.put(TableName.PRM_OFFICE,method.getAnnotation(DataFilter.class).prmOffice());
                type = method.getAnnotation(DataFilter.class).type();
            }
        }
        //访问目标方法的参数：
        Object[] args = point.getArgs();
        Map<String, String> map = new HashMap<>();
        map.put("dsf",DataScope.dataScopeFilter(tNameMap,type));
        boolean flag = false;
        for(int i = 0;i < args.length;i++){
            if(args[i] instanceof BaseEntity){
                args[i].getClass().getMethod("setSqlMap",Map.class).invoke(args[i],map);
                flag = true;
                break;
            }
        }
        if(flag == false){
            logger.error("未找到符合过滤条件的参数类型，参数需要继承BaseEntity");
        }
        //用改变后的参数执行目标方法
        Object returnValue = point.proceed(args);
        return  returnValue;
    }

    /**
     * 后置通知 用于拦截Service层注入数据过滤
     *
     * @param joinPoint 切点
     */
    @Before("pointCutMethod()")
    public void after(JoinPoint joinPoint) {
    }

    /**
     * 异常通知 用于拦截记录异常日志
     *
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        //1、开始时间
        long beginTime = System.currentTimeMillis();
        //线程绑定变量（该数据只有当前请求的线程可见）
        startTimeThreadLocal.set(beginTime);
        logger.error("异常时间: {}", new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS")
                .format(beginTime));
        String params = "";
        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
            for (int i = 0; i < joinPoint.getArgs().length; i++) {
                params += JSON.toJSONString(joinPoint.getArgs()[i]) + ";";
            }
        }
        LogUtils.saveLogAop(joinPoint,e,params);
        logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage(), params);
    }

}
